/**
 * 渲染水平文字，支持换行、设置行距。
 * @params errScale 指当一行的最后一个字操作该字宽度的百分比就进行换行。例如：0.6 则操个需要换行字宽度的60% 就将该字在下一行显示
 * */
CanvasRenderingContext2D.prototype.wrapText = function(text, { x = 0, y, maxWidth, lineHeight, fontLineHeight, errScale = 1, asc }) {
  if (typeof text !== 'string') {
    return
  }

  const context = this
  const canvas = context.canvas

  if (typeof maxWidth === 'undefined') {
    maxWidth = (canvas && canvas.width) || 300
  }
  if (typeof lineHeight === 'undefined') {
    lineHeight = (canvas && parseInt(window.getComputedStyle(canvas).lineHeight)) || parseInt(window.getComputedStyle(document.body).lineHeight)
  }
  if (typeof fontLineHeight === 'undefined') {
    fontLineHeight = parseFloat(context.font) || 12
  }
  if (typeof y === 'undefined') {
    y = fontLineHeight
  }

  const align = context.textAlign || 'left'
  if (align === 'center') {
    x = x + canvas.width / 2
  } else if (align === 'right') {
    x = x + canvas.width
  }

  const fontSize = parseFloat(context.font)
  y = fontSize * asc
  context.textBaseline = 'alphabetic'
  // 字符分隔为数组
  const arrText = text.split('')
  let line = ''
  const len = arrText.length
  for (let n = 0; n < len; n++) {
    if (arrText[n] === '\n') {
      context.fillText(line, x, y)
      line = ''
      y += lineHeight
    } else {
      const testLine = line + arrText[n]
      const metrics = context.measureText(testLine)
      const totalWidth = metrics.width
      const lastWidth = context.measureText(arrText[n]).width
      const testWidth = totalWidth + lastWidth * (errScale - 1)
      if (testWidth > maxWidth && n > 0) {
        context.fillText(line, x, y)
        line = arrText[n]
        y += lineHeight
      } else {
        line = testLine
      }
    }
  }
  context.fillText(line, x, y)
}

CanvasRenderingContext2D.prototype.letterSpacingText = function(text, x, y, letterSpacing) {
  const context = this
  const canvas = context.canvas

  if (!letterSpacing && canvas) {
    letterSpacing = parseFloat(window.getComputedStyle(canvas).letterSpacing)
  }
  if (!letterSpacing) {
    return this.fillText(text, x, y)
  }

  const arrText = text.split('')
  const align = context.textAlign || 'left'

  // 这里仅考虑水平排列
  const originWidth = context.measureText(text).width
  // 应用letterSpacing占据宽度
  const actualWidth = originWidth + letterSpacing * (arrText.length - 1)
  // 根据水平对齐方式确定第一个字符的坐标
  if (align === 'center') {
    x = x - actualWidth / 2
  } else if (align === 'right') {
    x = x - actualWidth
  }

  // 临时修改为文本左对齐
  context.textAlign = 'left'
  // 开始逐字绘制
  arrText.forEach(function(font) {
    const letterWidth = context.measureText(font).width
    context.fillText(font, x, y)
    // 确定下一个字符的横坐标
    x = x + letterWidth + letterSpacing
  })
  // 对齐方式还原
  context.textAlign = align
}

/* CanvasRenderingContext2D.prototype.fillTextVertical = function(text, { x = 0, y = 0, maxHeight, lineHeight, fontLineHeight, fontHeight = 0, letterSpacing = 0, errScale = 1, charRotate = false }) {
  if (typeof text !== 'string' || text.length === 0) {
    return
  }
  const context = this

  const arrText = text.split('')
  const arrWidth = arrText.map(function(letter) {
    return context.measureText(letter).width
  })

  const align = context.textAlign
  const baseline = context.textBaseline
  const fontSize = fontHeight || parseFloat(context.font)
  x = x - fontLineHeight / 2

  context.textAlign = 'center'
  // context.textBaseline = 'middle'
  context.textBaseline = 'alphabetic'

  y = y + (charRotate && arrText[0].charCodeAt(0) < 256 ? arrWidth[0] : fontSize) / 2
  const textArr = [[]]
  let rowIndex = 0
  // 开始逐字绘制
  arrText.forEach(function(letter, index) {
    // 是否需要旋转判断
    const code = letter.charCodeAt(0)
    let nowHeight = fontSize
    if (code <= 256 && charRotate) {
      context.translate(x, y)
      // 英文字符，旋转90°
      context.rotate(90 * Math.PI / 180)
      context.translate(-x, -y)
      nowHeight = arrWidth[index]
    } else if (charRotate && y !== fontSize / 2 && text.charCodeAt(index - 1) < 256) {
      y = y + arrWidth[index - 1] / 2
    }
    textArr[rowIndex].push(letter)
    context.fillText(letter, x, y)
    // 旋转坐标系还原成初始态
    context.setTransform(1, 0, 0, 1, 0, 0)
    // 确定下一个字符的纵坐标位置
    y = y + nowHeight + letterSpacing

    // 确定是不是最后一个字符
    if (arrText.length - 1 > index) {
      // 下面的 y + fontSize 是确定下个文字能否画全
      const isChar = arrText[index + 1].charCodeAt(0) <= 256
      const nextHeight = y + (charRotate && isChar ? arrWidth[index + 1] : fontSize) / 2 * errScale
      if (nextHeight > maxHeight) {
        x = x - lineHeight
        y = (charRotate && isChar ? arrWidth[index + 1] : fontSize) / 2
        textArr.push([])
        rowIndex++
      }
    }
  })
  context.saveTextArr = textArr
  // 水平垂直对齐方式还原
  context.textAlign = align
  context.textBaseline = baseline
}*/
/**
 * 绘制竖行文字，从右到左、从上到下进行绘制
 * */
CanvasRenderingContext2D.prototype.fillTextVertical = function(text, { x = 0, y = 0, maxHeight, lineHeight, fontLineHeight, fontHeight = 0, letterSpacing = 0, errScale = 1, asc, dec, textAlign = 'alphabetic', charRotate = false }) {
  if (typeof text !== 'string' || text.length === 0) {
    return
  }
  const context = this

  const arrText = text.split('')
  const arrWidth = arrText.map(function(letter) {
    return context.measureText(letter).width
  })

  const align = context.textAlign
  const baseline = context.textBaseline
  const fontSize = parseFloat(context.font)
  x = x - fontLineHeight / 2

  context.textAlign = 'center'
  // context.textBaseline = 'alphabetic'
  context.textBaseline = textAlign

  const fontSizeAsc = textAlign === 'alphabetic' ? fontSize * asc : 0
  const fontSizeDec = textAlign === 'alphabetic' ? fontSize * dec : fontHeight

  y = y + (charRotate && arrText[0].charCodeAt(0) < 256 ? arrWidth[0] / 2 : fontSizeAsc)
  const textArr = [[]]
  let rowIndex = 0
  // 开始逐字绘制
  arrText.forEach(function(letter, index) {
    // 是否需要旋转判断
    const code = letter.charCodeAt(0)
    let nowHeight = fontHeight
    if (code <= 256 && charRotate) {
      context.translate(x, y)
      // 英文字符，旋转90°
      context.rotate(90 * Math.PI / 180)
      context.translate(-x, -y)
      nowHeight = arrWidth[index]
    } else if (charRotate && y !== fontSizeAsc && text.charCodeAt(index - 1) < 256) {
      y = y + arrWidth[index - 1] / 2
    }
    textArr[rowIndex].push(letter)
    context.fillText(letter, x, y)
    // 旋转坐标系还原成初始态
    context.setTransform(1, 0, 0, 1, 0, 0)
    // 确定下一个字符的纵坐标位置
    y = y + nowHeight + letterSpacing

    // 确定是不是最后一个字符
    if (arrText.length - 1 > index) {
      // 下面的 y + fontSize 是确定下个文字能否画全
      const isChar = arrText[index + 1].charCodeAt(0) <= 256
      const nextHeight = y + (charRotate && isChar ? arrWidth[index + 1] / 2 : fontSizeDec) * errScale
      if (nextHeight > maxHeight) {
        x = x - lineHeight
        y = charRotate && isChar ? arrWidth[index + 1] / 2 : fontSizeAsc
        textArr.push([])
        rowIndex++
      }
    }
  })
  context.saveTextArr = textArr
  // 水平垂直对齐方式还原
  context.textAlign = align
  context.textBaseline = baseline
}

CanvasRenderingContext2D.prototype.fillTextVerticalA = function(text, { x = 0, lineHeight, fontLineHeight, fontHeight = 0, dec, charRotate = false }) {
  if (typeof text !== 'string' || text.length === 0) {
    return
  }
  const context = this
  const canvas = context.canvas

  const arrText = text.split('')
  const arrWidth = arrText.map(function(letter) {
    return context.measureText(letter).width
  })

  const align = context.textAlign
  const baseline = context.textBaseline
  const fontSize = parseFloat(context.font)
  const textArr = context.saveTextArr
  const len = textArr.length

  x = x + fontLineHeight / 2

  context.textAlign = 'center'
  context.textBaseline = 'alphabetic'

  let y = canvas.height
  const lastFont = arrText[arrText.length - 1]
  y = y - (charRotate && lastFont.charCodeAt(0) < 256 ? arrWidth[arrWidth.length - 1] / 2 : fontSize * dec)

  for (let i = textArr[len - 1].length - 1; i >= 0; i--) {
    const font = textArr[len - 1][i]
    const code = font.charCodeAt(0)
    let nowHeight = fontHeight
    if (code <= 256 && charRotate) {
      context.translate(x, y)
      // 英文字符，旋转90°
      context.rotate(90 * Math.PI / 180)
      context.translate(-x, -y)
      // 对于旋转的字符旋转后的高度等于宽度
      nowHeight = context.measureText(font).width
    } else if (charRotate && y !== canvas.height - fontSize * dec && textArr[len - 1].join('').charCodeAt(i + 1) < 256) {
      y = y - arrWidth[i - 1] / 2
    }
    context.fillText(font, x, y)
    // 旋转坐标系还原成初始态
    context.setTransform(1, 0, 0, 1, 0, 0)
    // 确定下一个字符的纵坐标位置
    y = y - nowHeight
  }
  const lastRow = []
  for (let i = textArr.length - 1; i >= 0; i--) {
    const fonts = textArr[i]
    if (i < len - 1) {
      const lastFont = fonts[fonts.length - 1]
      lastRow.push(lastFont)
    }
  }

  for (let i = 0, length = lastRow.length; i < length; i++) {
    const font = lastRow[i]
    x = x + lineHeight
    if (charRotate && font.charCodeAt(0) < 256) {
      const width = context.measureText(font).width
      y = canvas.height - width / 2
      context.translate(x, y)
      // 英文字符，旋转90°
      context.rotate(90 * Math.PI / 180)
      context.translate(-x, -y)
    } else {
      y = canvas.height - fontSize / 2
    }
    context.fillText(font, x, y)
    // 旋转坐标系还原成初始态
    context.setTransform(1, 0, 0, 1, 0, 0)
  }

  // 水平垂直对齐方式还原
  context.textAlign = align
  context.textBaseline = baseline
}

/**
 * 水平方式 从上到下 扫描
 * */
function topScanBottom(imageData) {
  const { data, width } = imageData
  const length = data.length
  let i = 3
  for (i; i < length; i = i + 4) {
    if (data[i] > 10) {
      break
    }
  }
  // 除掉4位颜色值
  const c4 = (i + 1) / 4
  // 除掉宽度就是列数。
  const cW = c4 / width
  return Math.floor(cW)
}

/**
 * 水平方式 从下到上 扫描
 * */
function bottomScanTop(imageData) {
  const { data, width, height } = imageData
  let i = data.length - 1
  for (i; i > 0; i = i - 4) {
    if (data[i] > 10) {
      break
    }
  }
  // 除掉4位颜色值
  const c4 = (i + 1) / 4
  // 除掉宽度就是列数。
  const cW = c4 / width
  return height - Math.ceil(cW)
}

/**
 * 垂直方式 从左到右 扫描
 * */
function leftScanRight(imageData) {
  const { data, width, height } = imageData
  const wLength = width * 4
  const hLength = height * 4
  let i = 3
  let j = 0
  let back = false
  for (i; i < wLength; i = i + 4) {
    j = 0
    for (j; j < hLength; j++) {
      if (data[i + width * 4 * j] > 10) {
        back = true
        break
      }
    }
    if (back) {
      break
    }
  }
  return (i + 1) / 4
}

/**
 * 垂直方式 从右到左 扫描
 * */
function rightScanLeft(imageData) {
  const { data, width, height } = imageData
  let i = width * 4 - 1
  let back = false
  for (i; i > 0; i = i - 4) {
    for (let j = height * 4; j > 0; j--) {
      if (data[i + width * 4 * j] > 10) {
        back = true
        break
      }
    }
    if (back) {
      break
    }
  }
  return width - (i + 1) / 4
}

/**
 * 用于获取文字上下左右的空白
 * */
function getHorizontalRender(text, { fontSize, fontFamily, width, height, fontLineHeight, lineHeight, letterSpacing = 0, asc, errScale = 0.8 }) {
  const canvas = document.createElement('canvas')
  canvas.width = width + fontSize * 2
  canvas.height = height + fontSize * 2
  const context = canvas.getContext('2d')
  context.font = `${fontSize}px ${fontFamily}`
  context.textAlign = 'left'
  context.textBaseline = 'top'
  context.wrapText(text, {
    maxWidth: width,
    y: 0,
    fontLineHeight,
    lineHeight,
    letterSpacing,
    asc,
    errScale
  })
  const imageData = context.getImageData(0, 0, canvas.width, canvas.height)
  const top = topScanBottom(imageData)
  const left = leftScanRight(imageData)
  const shamRight = rightScanLeft(imageData)
  // 清空画布
  context.clearRect(0, 0, canvas.width, canvas.height)
  // 重绘 居右文字
  context.textAlign = 'right'
  context.wrapText(text, {
    maxWidth: width,
    y: 0,
    fontLineHeight,
    lineHeight,
    letterSpacing,
    asc,
    errScale
  })
  const rightImageData = context.getImageData(0, 0, canvas.width, canvas.height)
  const right = rightScanLeft(rightImageData)
  const bottom = bottomScanTop(rightImageData)
  const noBlankHeight = imageData.height - top - bottom
  const row = (noBlankHeight - fontLineHeight + lineHeight) / lineHeight
  const totalHeight = fontLineHeight + lineHeight * (Math.ceil(row) - 1)
  const realBottom = totalHeight - top - noBlankHeight

  return {
    top,
    bottom: realBottom,
    left,
    right,
    width: canvas.width - left - shamRight
  }
}

/**
 * 用于获取竖行文字的上下左右空白
 * */
function getVerticalRender(text, { fontSize, fontFamily, width, height, fontLineHeight, lineHeight, letterSpacing = 0, asc, dec, leading = 0, fontHeight = 0, errScale = 0.8, charRotate = false }) {
  const canvas = document.createElement('canvas')
  canvas.width = width + fontSize * 2
  canvas.height = height + fontSize * 2
  const context = canvas.getContext('2d')
  context.font = `${fontSize}px ${fontFamily}`
  asc = Math.abs(asc)
  dec = Math.abs(dec)
  let textAlign = 'alphabetic'
  if (Math.abs(fontHeight - (asc + dec) * fontSize) > 2 && asc + dec !== 1) {
    if (asc + dec - leading !== 1) {
      textAlign = 'top'
    } else {
      asc -= leading / 2
      dec -= leading / 2
    }
  }
  context.fillTextVertical(text, { x: canvas.width, lineHeight, maxHeight: height, fontLineHeight, fontHeight, letterSpacing, asc, dec, textAlign, errScale, charRotate })
  const imageData = context.getImageData(0, 0, canvas.width, canvas.height)
  const top = topScanBottom(imageData)
  const right = rightScanLeft(imageData)
  const bottomA = bottomScanTop(imageData)
  context.clearRect(0, 0, canvas.width, canvas.height)
  context.fillTextVerticalA(text, { x: 0, lineHeight, fontLineHeight, fontHeight, dec, charRotate })
  const imageDataA = context.getImageData(0, 0, canvas.width, canvas.height)
  const bottom = bottomScanTop(imageDataA)
  const left = leftScanRight(imageDataA)
  return {
    top,
    right,
    bottom,
    left,
    height: canvas.height - top - bottomA
  }
}

export default {
  topScanBottom,
  bottomScanTop,
  leftScanRight,
  rightScanLeft,
  getHorizontalRender,
  getVerticalRender
}
